package com.zhanglu.fun.services.authentication.login;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.zhanglu.fun.services.authentication.bean.*;
import com.zhanglu.fun.services.authentication.client.DataCenterClient;
import com.zhanglu.fun.tookit.jwt.JwtUtil;
import com.zhanglu.fun.tookit.jwt.OldJwtUtil;
import com.zhanglu.fun.tookit.jwt.TokenInfo;

import lombok.extern.slf4j.Slf4j;

/**
 * @author zhanglu
 */
@Service
@Slf4j
public class LoginService {
    @Autowired
    private DataCenterClient dataCenterClient;

    private final int timeOutType = Calendar.MINUTE;//过期时间类型
    private final int minuteTimeOut = 60;//数据库中华令牌过期
    private final int tokenTimeOut = -10;//token里面令牌和数据库中令牌时间差,(minuteTimeOut + tokenTimeOut)是token中令牌过期时间

    public UserResponse login(String account, String password) {
        log.info("login params:[username is {} | password is {}]", account, password);
        User user = dataCenterClient.getUserByAccount(account, password);
        if (user == null) {
            return null;
        }

        AuthToken authToken = dataCenterClient.getAuthTokenByUserId(user.getId());
        List<String> roles = dataCenterClient.getApplicationRolesByUserId(user.getId()).stream().map(ApplicationRole::getRoleName).collect(Collectors.toList());
        log.info("get roles result:[the user is {} | and the roles are {}]", user.getNickName(), roles);
        Date expireDate = getExpiresDate().getTime();
        String token = getToken(user, roles, expireDate);
        log.info("token is {}", token);

        if (authToken != null) {
            authToken.setExpiresDate(expireDate);
            authToken.setToken(token); // 加上这一行，作用是只允许一个人登陆，不允许同时同账号多登陆
            boolean result = dataCenterClient.updateAuthTokenById(authToken);
            log.debug("此用户已经有token,更新token:[更新结果：{}]", result);
        }else{
            boolean result = dataCenterClient.addAuthTokenByToken(new AuthToken()
                    .setToken(token)
                    .setExpiresDate(expireDate)
                    .setUserId(user.getId()));
            log.debug("用户{}登陆是否成功->{}:[创建token：{}]", user.getNickName(), result, token);
        }

        UserResponse response = new UserResponse();
        BeanUtils.copyProperties(user, response);
        response.setToken(token);
        response.setRoles(StringUtils.join(roles, ","));
        return response;
    }

    public IsLogin isLogin(String token) {
        log.debug("Is login params:[token is {}]", token);
        AuthToken authToken = dataCenterClient.getAuthTokenByToken(token);

        IsLogin isLogin = new IsLogin().setLogin(false);

        if (authToken == null) {
            log.debug("token不存在");
            return isLogin;
        }

        if (authToken.getExpiresDate().getTime() < new Date().getTime()) { //token超时失效
            boolean result = dataCenterClient.deleteAuthTokenByToken(token);
            log.debug("token超时,删除token:[删除结果：{}]", result);
            return isLogin;
        }

        Date now = getExpiresDate().getTime();

        TokenInfo oldToken = OldJwtUtil.parseJWT(token);
        oldToken.setExpiresDate(getTokenExpireDate(now).getTime());
        String newToken = OldJwtUtil.createJWT(oldToken);

        authToken.setExpiresDate(now).setToken(newToken);
        boolean updateOK = dataCenterClient.updateAuthTokenById(authToken);
        log.debug("update token is OK-->{}", updateOK);
        isLogin.setToken(newToken).setLogin(updateOK);
        return isLogin;
    }

    private Calendar getExpiresDate() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(timeOutType, minuteTimeOut);
        return calendar;
    }

    private String getToken(User user, List<String> roles, Date expireDate) {
        TokenInfo token = new TokenInfo().setCreateDate(new Date())
                .setExpiresDate(getTokenExpireDate(expireDate).getTime())
                .setEmail(user.getEmail())
                .setNickName(user.getNickName())
                .setRoles(Objects.isNull(roles) || roles.size() <= 0 ? "" : roles.stream().collect(Collectors.joining(",")));
        return OldJwtUtil.createJWT(token);
    }

    private Calendar getTokenExpireDate(Date expireDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(expireDate);
        calendar.add(timeOutType, tokenTimeOut); // 时间差10分钟赋给token。
        return calendar;
    }
}
